package org.gjy.m8.concurrent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 线程池与屏障数量匹配
 * 线程池核心线程数（THREAD_COUNT）必须 ≥ CyclicBarrier 的 parties 值（THREAD_COUNT）。
 * 若不匹配，部分线程可能因线程池资源不足而无法执行，导致屏障永远无法触发（死锁）。
 * <p>
 * 分阶段同步控制
 * 每个任务在完成阶段工作后调用 barrier.await()，进入等待状态。
 * 当所有任务都到达屏障点时，触发 Runnable 屏障动作（可选），然后所有线程自动释放
 * <p>
 * 超时与异常处理
 * 使用 await(timeout, unit) 设置超时（此处为 2 秒），避免因线程阻塞导致系统僵死。
 * 超时或中断会抛出 TimeoutException/BrokenBarrierException，需捕获处理。
 * <p>
 * 屏障的重用性
 * CyclicBarrier 在释放线程后自动重置，可重复用于下一阶段
 * 若需手动重置（如异常后恢复），可调用 reset() 方法。
 *
 * @author gjy
 * @version 1.0
 * @since 2025-06-30 17:04:23
 */
public class CyclicBarrierTest {
    private static final Logger log = LoggerFactory.getLogger(CyclicBarrierTest.class);

    // 任务阶段数
    private static final int PHASE_COUNT = 3;
    // 线程数 = CyclicBarrier 的 parties 数
    private static final int THREAD_COUNT = 4;

    public static void main(String[] args) {
        // 1. 创建线程池（核心线程数必须 ≥ CyclicBarrier 的 parties 数）
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);

        // 2. 创建 CyclicBarrier，指定 parties 和屏障动作（每阶段结束执行）
        CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT, () -> System.out.println("【屏障动作】所有线程完成当前阶段，继续下一阶段"));

        // 3. 提交任务
        for (int i = 0; i < THREAD_COUNT; i++) {
            final int taskId = i;
            executor.submit(() -> {
                try {
                    Random random = new Random();
                    // 执行 3 个阶段
                    for (int phase = 1; phase <= PHASE_COUNT; phase++) {
                        // 模拟阶段耗时
                        int workTime = random.nextInt(10000) + 1000;
                        Thread.sleep(workTime);
                        System.out.printf("任务-%d 完成阶段%d（耗时%dms）%n", taskId, phase, workTime);
                        // 等待其他线程到达屏障
                        // barrier.await(2, TimeUnit.SECONDS); // 设置超时避免死锁
                        barrier.await();
                    }
                    System.out.printf("任务-%d 全部完成！%n", taskId);
                } catch (InterruptedException | BrokenBarrierException e) {
                    System.err.printf("任务-%d 中断: %s%n", taskId, e.getMessage());
                }
            });
        }
        // 4. 关闭线程池
        executor.shutdown();
    }
}